<?php


namespace services\base;

use common\helpers\ArrayHelper;
use http\Message\Body;
use Yii;
use common\components\Service;
use common\helpers\CommonHelper;
use common\models\base\BodyParts;
use common\models\patient\BodyParts as PatientBodyParts;
use common\models\patient\User;
use yii\data\Pagination;
use yii\db\Exception;

class BodyPartsServer extends Service
{
    /**
     * 查找列表
     *
     * @param array $condition
     * @return array|\yii\db\ActiveRecord[]
     */
    public function findList(array $condition = [])
    {
        $query = BodyParts::find();

        // select
        isset($condition['select']) && $query->select($condition['select']);

        // condition
        isset($condition['id']) && $query->andWhere(['id' => $condition['id']]);
        isset($condition['status']) && $query->andWhere(['status' => $condition['status']]);
        isset($condition['type']) && $query->andWhere(['type' => $condition['type']]);
        isset($condition['pid']) && $query->andWhere(['pid' => $condition['pid']]);

        // indexBy
        isset($condition['indexBy']) && $query->indexBy($condition['indexBy']);

        return $query->asArray()->all();
    }

    /**
     * 患者部位二级列表
     *
     * @return array
     */
    public function positionList($page = 1, $pageSize = 10,$params)
    {
        $status = $params['status'] ?? 0;

        $query = BodyParts::find()
            ->where([
                'pid' => 0
            ]);

        if (isset($params['type'])) {
            $query->andWhere(['type' => $params['type']]);
        }

        if ($status == BodyParts::STATUS_ENABLE) {
            $query->andWhere(['status' => BodyParts::STATUS_ENABLE]);
        } else {
            $query->andWhere(['<>', 'status', BodyParts::STATUS_DELETE]);
        }

        $pagination = new Pagination([
            'defaultPageSize' => $pageSize,
            'totalCount' => $query->count(),
            'validatePage' => false,
        ]);

        $bodyArray = $query->asArray()
            ->offset($pagination->offset)
            ->limit($pagination->limit)
            ->orderBy(['status' => SORT_DESC, 'sort' => SORT_ASC])
            ->all();

        $list = $this->childData($bodyArray,$status);

        return ['list' => $list, 'total' => (int)$pagination->totalCount, 'pageSize' => (int)$pageSize, 'page' => (int)$page];

    }

    /*
     * 二级分类,获取 第二级
     * */
    public function childData($params,$status)
    {
        $pidIds = array_column($params, 'id');
        $query = BodyParts::find()
            ->where(['pid' => $pidIds]);

        if (isset($params['type'])) {
            $query->andWhere(['type' => $params['type']]);
        }

        if ($status == BodyParts::STATUS_ENABLE) {
            $query->andWhere(['status' => BodyParts::STATUS_ENABLE]);
        } else {
            $query->andWhere(['<>', 'status', BodyParts::STATUS_DELETE]);
        }

        $data = $query->orderBy(['status' => SORT_DESC, 'sort' => SORT_ASC])
            ->asArray()
            ->all();

        $tempArray = array_column($params, null, 'id');

        foreach ($tempArray as $key => $value) {
            $tempArray[$key]['children'] = [];
        }

        foreach ($data as $value) {

            $tempArray[$value['pid']]['children'][] = $value;

        }

        $bodyArray = [];
        foreach ($tempArray as $value) {
            $bodyArray[] = $value;
        }
        return $bodyArray;
    }


    /**
     *
     * @apiDescription 处理分类数组,将子类放到父类下面去
     **
     * @apiSuccess {Number} code    状态码，0：请求成功
     * @apiSuccess {String} message   提示信息
     * @apiSuccess {Object} data    返回数据
     * @param $list  需要处理的分类数组
     * @param string $pk 主键名称
     * @param string $pid 父级id
     * @param string $child 子类数组名
     * @param int $root 默认0 从根父类开始计算
     * @return array
     */
    public function make_tree($list, $pk = 'id', $pid = 'pid', $child = 'children', $root = 0)
    {
        $tree = array();

        foreach ($list as $key => $val) {

            if ($val[$pid] == $root) {
                //获取当前$pid所有子类
                unset($list[$key]);

                if (!empty($list)) {
                    //查询该分类下面所有的子分类
                    $child = $this->make_tree($list, $pk, $pid, $child, $val[$pk]);

                    if (!empty($child)) {
                        $val['children'] = $child;
                    }
                }
                $val['value'] = $val['id'];
                $val['title'] = $val['body_parts_name'];
                $val['expand'] = true;
                $tree[] = $val;
            }
        }
        return $tree;
    }

    /**
     * @apiGroup 分组名称
     * @apiName 名称
     * @apiVersion 1.0.0
     *
     * @apiDescription 更新分类名称,分类排序,分类父级,分类状态
     *
     * @apiParam {String} $param1  参数说明
     * @param $params 接受参数
     * @apiParam {int} $id  分类
     * @apiParam {int} $pid 父级id
     * @apiParam {String} $body_parts_name  分类名
     * @apiParam {int} $sort  排序号
     * @apiParam {int} $sort  排序号
     *
     * @apiSuccess {Number} code    状态码，0：请求成功
     * @apiSuccess {String} message   提示信息
     * @apiSuccess {Object} data    返回数据
     * @return bool
     */
    public function positionUpdate($params)
    {
        $id = $params['id'];
        $pid = $params['pid'] ?? 0;
        $body_parts_name = $params['body_parts_name'];
        $sort = $params['sort'] ?? 0;
        $status = $params['status'];
        if ($status != BodyParts::STATUS_ENABLE) {
            $status = BodyParts::STATUS_INVALID;
        }
        $model = BodyParts::findOne($id);

        if (!$model) {
            return CommonHelper::api(422, '该分类不存在');
        }

        if ($pid == $id) {
            return CommonHelper::api(422, '不可以设为自己的下级');
        }

        //如果转换父级,该类下有子类不能进行转换
        if ($pid != $model->pid) {
            /*$where = ['and'];
            $where[] = ['pid' => $id];
            $where[] = ['<>', 'status', BodyParts::STATUS_DELETE];*/
            $childCount = BodyParts::find()
                ->where([
                    'and',
                    ['pid' => $id],
                    ['type' => $model->type],
                    ['!=', 'status', BodyParts::STATUS_DELETE],
                ])
                ->count();

            if ($childCount > 0) {
                return CommonHelper::api(422, '该分类有子类不能移动');
            }
        }

        // 父级名称不能相同
        if ($pid == 0 && $body_parts_name != $model->body_parts_name) {
            $repeat = BodyParts::find()
                ->where([
                    'body_parts_name' => $body_parts_name,
                    'pid' => 0,
                    'type' => $model->type,
                ])
                ->andWhere(['!=', 'status', BodyParts::STATUS_DELETE])
                ->one();

            // 判断修改的分类名有没有重复的,修改本条数据不判断
            if (!empty($repeat) && $repeat->id != $id) {
                return CommonHelper::api(422, '命名重复');
            }
        }

        //查询状态是不是可以修改(下级在使用的不能禁用,上级被禁用的下级不能启用)
        $data = $this->deleteAndDisable($pid, $id, $status);

        if ($data['code'] == 200) {
            $model->status = $status;
        } else {
            return CommonHelper::api(422, $data['message']);
        }

        // 原部位名称
        $oldBodyPartsName = $model->body_parts_name;
        $model->body_parts_name = $body_parts_name;
        $model->sort = $sort;
        $model->pid = $pid;
        $model->updated_at = time();

        // 患者绑定部位
        $patientBodyParts = Yii::$app->services->patientBodyParts->findList([
            'body_parts_id' => $id,
            'status' => \common\models\patient\BodyParts::STATUS_ENABLE,
        ]);

        $patientUserList = Yii::$app->services->patientUser->findList([
            'id' => array_column($patientBodyParts, 'patient_user_id')
        ]);
        foreach ($patientUserList as $row) {
            $result = substr_replace($row['patient_body_parts_name'], $body_parts_name, strpos($row['patient_body_parts_name'], $oldBodyPartsName), strlen($oldBodyPartsName));
            $attr = [
                'patient_body_parts_name' => $result
            ];
            User::updateAll($attr, ['id' => $row['id']]);
        }

        if ($model->save()) {
            return CommonHelper::api(200, '更新成功');
        }
        return CommonHelper::api(422, '更新失败');
    }

    /**
     * 父部位列表
     *
     * @param array $params
     * @return array|\yii\db\ActiveRecord[]
     */
    public function fatherList(array $params = [])
    {
        $query = BodyParts::find()
            ->select('id,body_parts_name')
            ->where(['<>', 'status', BodyParts::STATUS_DELETE])
            ->andWhere([
                'pid' => 0,
            ]);

        if (isset($params['type'])) {
            $query->andWhere(['type' => $params['type']]);
        }

        $bodyArray = $query->asArray()
            ->orderBy(['sort' => SORT_ASC])
            ->all();
        return $bodyArray;
    }


    /**
     * 新增部位
     *
     * @param $params
     * @return array
     * @throws Exception
     */
    public function positionCreate($params)
    {
        $namesStr = isset($params['body_parts_name']) ? $params['body_parts_name'] : '';
        $namesArray = array_unique(explode(',', $this->strFormat($namesStr)));
        $pid = $params['pid'] ?? 0;
        $sort = $params['sort'] ?? null;
        $params['type'] = $params['type'] ?? BodyParts::TYPE_NORMAL;

        //如果sort为空则,查询当前类的最大排序数,依次递增
        if (empty($sort)) {
            $sortLastModel = BodyParts::find()
                ->where([
                    'pid' => $pid,
                    'type' => $params['type'],
                ])
                ->orderBy(['sort' => SORT_DESC])
                ->one();
            $sort = !empty($sortLastModel) ? $sortLastModel->sort : 0;
            $sort++;
        }

        // 父级名称不能相同
        if ($pid == 0) {
            $repeat = BodyParts::find()
                ->select('id')
                ->where([
                    'body_parts_name' => $namesArray,
                    'pid' => 0,
                    'type' => $params['type'],
                ])
                ->andWhere(['!=', 'status', BodyParts::STATUS_DELETE])
                ->asArray()
                ->one();

            if ($repeat) {
                return CommonHelper::json(422, '名称重复,不可创建');
            }
        }

        $insertData = [];
        foreach ($namesArray as $v) {
            $insertData[] = [
                'pid' => $pid,
                'body_parts_name' => trim($v),
                'sort' => $sort++,
                'type' => $params['type'],
                'created_at' => time(),
                'updated_at' => time(),
            ];
        }

        Yii::$app->db->createCommand()
            ->batchInsert(BodyParts::tableName(),
                ['pid', 'body_parts_name', 'sort', 'type', 'created_at', 'updated_at'],
                $insertData)
            ->execute();

        return CommonHelper::json(200, '创建成功');
    }

    /**
     * @param $pid
     * @param $id
     * @param $status
     * @return bool
     * @apiGroup 分组名称
     * @apiName 名称
     * @apiVersion 1.0.0
     *
     * @apiDescription 分类删除和停用
     *
     * @apiParam {String} $param1  参数说明
     *
     * @apiSuccess {Number} code    状态码，200：请求成功
     * @apiSuccess {String} message   提示信息
     * @apiSuccess {Object} data    返回数据
     */
    public function deleteAndDisable($pid, $id, $status)
    {
        // 停用和删除 要判断下级分类有没有在使用
        if ($status == BodyParts::STATUS_INVALID || $status == BodyParts::STATUS_DELETE) {
            $count = BodyParts::find()
                ->where(['status' => BodyParts::STATUS_ENABLE, 'pid' => $id])
                ->count();

            if ($count > 0) {
                return CommonHelper::json(422, '该分类有子类在使用,请先删除子类');
            }
            //后面的应用场景中有使用也不可以停用和删除(后期功能完善)
            return CommonHelper::json(200, '可以更新');
        } elseif ($status == BodyParts::STATUS_ENABLE) {  //被停用的重新启用,要看上级有没有启用

            //根目录没有上级,可直接开启
            if ($pid == 0) {
                return CommonHelper::json(200, '可以更新');
            }
            $count = BodyParts::find()
                ->where(['status' => BodyParts::STATUS_ENABLE, 'id' => $pid])
                ->count();

            if ($count > 0) {
                return CommonHelper::json(200, '可以更新');
            }
            return CommonHelper::json(422, '请先将上级设为开启状态');
        }
    }


    /**
     * 编辑部位状态
     *
     * @param int $id
     * @param int $status
     * @return array
     * @throws \Exception
     * @author wangxiang
     */
    public static function changeStatus(int $id, int $status)
    {
        $model = BodyParts::findOne($id);
        $model->status = $status;
        if (!$model->save()) {
            throw new \Exception(json_encode($model->errors), 500);
        }

        return ['id' => $id, 'status' => $status];
    }

    /**
     * 字符串格式转换,去掉空格,替换中文逗号
     * @param $str
     * @return mixed|string
     */
    public function strFormat($str)
    {
        if (!$str) {
            return '';
        }
        $str = str_replace(' ', '', $str);
        $str = str_replace('，', ',', $str);
        return $str;
    }

    public static function trueDelete(int $id)
    {
        $bodyPartsArray = BodyParts::find()
            ->select('id, body_parts_name, pid')
            ->where(['id' => $id])
            ->asArray()
            ->all();

        if (!$bodyPartsArray) {
            return ['code' => 422, 'message' => '该部位不存在'];
        }

        $transaction = Yii::$app->db->beginTransaction();
        try {
            $member = Yii::$app->user->identity->member;

            // 如果是一级部位
            if ($bodyPartsArray[0]['pid'] == 0) {

                // 需要筛选全部子集批量删除
                $childBodyParts = BodyParts::find()
                    ->select('id, body_parts_name, pid')
                    ->andWhere(['>', 'pid', 0])
                    ->asArray()
                    ->all();

                $childBodyArray = ArrayHelper::getChilds($childBodyParts,$id);

                foreach ($childBodyArray as $value) {
                    $bodyPartsArray[] = $value;
                }
            }

            foreach ($bodyPartsArray as $data) {
                $insertData[] = [
                    'project_id' => 0,
                    'delete_id' => $data['id'],
                    'delete_name' => $data['body_parts_name'],
                    'delete_table' => BodyParts::tableName(),
                    'effect_table' => '【' . User::tableName() . '（patient_body_parts_name）】' . '【' . PatientBodyParts::tableName() . '】',
                    'operator_id' => $member->id,
                    'operator_name' => $member->realname,
                    'created_at' => time(),
                    'updated_at' => time()
                ];
            }

            // 删除部位表
            $ids = array_column($bodyPartsArray,'id');
            // 删除部位
            $data = BodyParts::deleteAll(['id' => $ids]);
            // 查询部位关联表中的,patient_user_id
            $patientUserIds= PatientBodyParts::find()
                ->where(['body_parts_id' => $ids])
                ->groupBy('patient_user_id')
                ->column();

            // 删除部位关联表
            PatientBodyParts::deleteAll(['body_parts_id' => $ids]);

            // 更新患者部位冗余字段
            $newPatientBody = PatientBodyParts::find()
                ->select('a.patient_user_id,GROUP_CONCAT(b.body_parts_name) as body_parts_name')
                ->alias('a')
                ->where([
                    'a.patient_user_id' => $patientUserIds,
                    'a.status' => PatientBodyParts::STATUS_ENABLE
                ])
                ->leftJoin(BodyParts::tableName() . ' b','a.body_parts_id = b.id')
                ->groupBy('a.patient_user_id')
                ->asArray()
                ->all();

            foreach ($newPatientBody as $item) {
                User::updateAll(['updated_at' => time(), 'patient_body_parts_name' => $item['body_parts_name']],['id' => $item['patient_user_id']]);
            }

            $transaction->commit();
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }

        if (!$data) {
            return ['code' => 422, 'message' => '删除失败'];
        }
        return ['code' => 200, 'message' => '删除成功'];

    }

}
